package com.xcity.tools.serverNew;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;

import naga.x.platform2.app.Channel;
import naga.x.platform2.app.model.GameServer;
import naga.x.util.CommonUtils;
import naga.x.util.IOUtils;

/**
 * 开新服<br/>
 * 定义配置文件
 * @author yang.li
 *
 */
public class NewServer {

	static final int KEY_LEN = 32;
	static int portInit = 5000; // !!! nginx: +10, proxy: +20, server: +30, http: +40
	
	// 游戏服配置
	/** 服务器id（唯一） */
	public static int serverId = 7; // !!!
	/** 服务器名 */
	public static String serverName = "阿尔卑斯"; // !!!
	public static String serverDesc = "";
	/** 服务器ip */
	public static String serverHost = "123.206.95.193"; // !!!
	/** 服务器代理连接端口（nginx->proxy server->game server） */
	public static int proxyPort = portInit + 30;//4030;
	/** 服务器直连端口 */
	public static int directPort = portInit + 10;//4010;
	/** 服务器http端口（充值回调、GM连接） */
	public static int httpPort = portInit + 40;//4040;
	/** 服务器秘钥 */
	public static String key = CommonUtils.randomText(KEY_LEN);
	/** 服务器目录 */
	public static String serverDir = "/data/game-server-v3/city-server" + serverId;
	/** 服务器数据库url */
//	public static String dbUrl = "jdbc:mysql://rdsd09ffm5143cy22qd4.mysql.rds.aliyuncs.com:3306/city_pro_03";
	public static String dbUrl = "jdbc:mysql://127.0.0.1:3306/city7_v3"; // !!!
	/** 服务器数据库用户名 */
//	public static String dbUser = "xtoneapp";
	public static String dbUser = "city"; // !!!
	/** 服务器数据库密码 */
//	public static String dbPwd = "Xtone35App16Lb";
	public static String dbPwd = "htEGEieNzX"; // !!!
	
	public static Channel channel = Channel.OFFICIAL;
	public static GameServer.State state = GameServer.State.NEW;
	
	// 代理服配置
	/** 代理服务器端口 */
//	public static int[] proxyServerPorts = { 3020, 3021 };
	public static int[] proxyServerPorts = { portInit + 20, portInit + 21 };
	/** 默认启用代理服务器 */
	public static boolean proxyServerEnable = true;
	
	// 游戏服启动参数
	public static String Xms = "2g";
	public static String Xmx = "2g";
	
	public static File baseDir = IOUtils.getResourceAsFile("new_server_template");
	public static File destDir = new File("C:/Users/yang.li/Desktop/server_release/new_servers");
	public static File dataDir = new File("C:/Users/yang.li/Desktop/server_release/data");
	
	static class Holder {
		static String serverConfig;
		static String serverDbConfig;
		static String startupShell;
		static String nginxConfig;
		static String[] proxyServerConfigs;
	}
	
	public static void main(String[] args) {
		prepare();
		
		// 修改游戏服配置 config.json
		Holder.serverConfig = makeServerConfig();
		// 修改游戏服数据库配置 mybatis.xml
		Holder.serverDbConfig = makeServerDbConfig();
		// 修改游戏服启动参数
		Holder.startupShell = makeServerStartupShell();
		// 修改nginx配置
		Holder.nginxConfig = makeNginxConfig();
		// 代理服务器配置
		Holder.proxyServerConfigs = makeProxyServerConfig();

		copyFiles();
		createSql();
		log();
		System.out.println("ok:" + serverId);
	}
	
	private static void createSql() {
		String sql = "INSERT INTO `game_server` VALUES({id}, '{name}', {channel}, '{host}', {port}, {httpPort}, '{key}', {state}, {weight}, '{dir}', '{desc}');";
		sql = sql.replace("{id}", String.valueOf(serverId))
				.replace("{name}", serverName)
				.replace("{channel}", String.valueOf(channel.ordinal()))
				.replace("{host}", serverHost)
				.replace("{port}", String.valueOf(directPort))
				.replace("{httpPort}", String.valueOf(httpPort))
				.replace("{key}", key)
				.replace("{state}", String.valueOf(state.ordinal()))
				.replace("{weight}", String.valueOf(10))
				.replace("{dir}", serverDir)
				.replace("{desc}", serverDesc);
		IOUtils.write(new File(destDir, "GAME_SERVERS.sql"), sql, IOUtils.UTF8, true);
	}
	
	private static void log() {
		File file = new File(destDir, "LOG.txt");
		StringBuilder buf = new StringBuilder(10240);
		buf.append("serverId=").append(serverId).append(System.lineSeparator());
		buf.append("serverName=").append(serverName).append(System.lineSeparator());
		buf.append("serverHost=").append(serverHost).append(System.lineSeparator());
		buf.append("serverDir=").append(serverDir).append(System.lineSeparator());
		if (proxyServerEnable) {
			buf.append("nginx direct port=").append(directPort);
			buf.append(" -> proxy server port=");
			for (int i = 0; i < proxyServerPorts.length; i++) {
				if (i != 0) {
					buf.append('/');
				}
				buf.append(proxyServerPorts[i]);
			}
			buf.append(" -> game server port=").append(proxyPort).append(System.lineSeparator());
		} else {
			buf.append("game server direct port=").append(directPort).append(System.lineSeparator());
		}
		buf.append("httpPort=").append(httpPort).append(System.lineSeparator());
		buf.append("db=").append(dbUrl).append(System.lineSeparator()).append(System.lineSeparator());
		buf.append("=======================================").append(System.lineSeparator());
		IOUtils.write(file, buf.toString(), IOUtils.UTF8, true);
	}
	
	private static void prepare() {
		if (!destDir.exists()) {
			destDir.mkdirs();
		}
	}
	
	static String makeServerConfig() {
		File configFile = new File(baseDir, "server/config/config.json");
		JSONObject json = JSON.parseObject(IOUtils.read(configFile, IOUtils.UTF8), Feature.OrderedField);
		json.put("serverId", serverId);
		json.put("serverName", serverName);
		json.put("websocket.remoteAddr", serverHost);
		if (proxyServerEnable) {
			json.put("proxy.port", proxyPort); // 游戏服供代理服连接的端口
			json.remove("websocket.port");
		} else {
			json.put("websocket.port", directPort); // 游戏服直连端口
			json.remove("proxy.port");
		}
		json.put("http.port", httpPort);
		json.put("key", key);
		
		String s = JSON.toJSONString(json, true);
//		System.out.println(s);
		return s;
	}
	
	static String makeServerDbConfig() {
		File file = new File(baseDir, "server/config/mybatis.xml");
		String text = IOUtils.read(file, IOUtils.UTF8);
		text = text.replace("{dbUrl}", dbUrl)
				.replace("{dbUser}", dbUser)
				.replace("{dbPwd}", dbPwd);
//		System.out.println(text);
		return text;
	}
	
	static String makeServerStartupShell() {
		File file = new File(baseDir, "server/startup.sh");
		String text = IOUtils.read(file, IOUtils.UTF8);
		text = text.replace("{xms}", Xms).replace("{xmx}", Xmx);
		return text;
	}
	
	static String makeNginxConfig() {
		if (proxyServerEnable) {
			File file = new File(baseDir, "nginx.proxy.conf");
			String text = IOUtils.read(file, IOUtils.UTF8);
			text = text.replace("{serverName}", serverName)
					.replace("{directPort}", String.valueOf(directPort))
					.replace("{serverNameEn}", "city_server" + serverId);
			String s = "server 127.0.0.1:{proxyPort} weight=5 max_fails=3 fail_timeout=30s;";
			StringBuilder buf = new StringBuilder();
			for (int port : proxyServerPorts) {
				String ss = s.replace("{proxyPort}", String.valueOf(port));
				buf.append(ss).append(System.lineSeparator()).append("    ");
			}
			text = text.replace("{proxyServers}", buf);
//			System.out.println(text);
			return text;
		}
		return null;
	}
	
	static String[] makeProxyServerConfig() {
		if (proxyServerEnable) {
			File file = new File(baseDir, "proxy_server/config/config.json");
			JSONObject json = JSON.parseObject(IOUtils.read(file, IOUtils.UTF8), Feature.OrderedField);
			String[] configs = new String[proxyServerPorts.length];
			for (int i = 0; i < configs.length; i++) {
				json.put("websocket.remoteAddr", serverHost);
				json.put("websocket.port", proxyServerPorts[i]);
				json.put("gameserver.port", proxyPort);
				configs[i] = JSON.toJSONString(json, true);
			}
			return configs;
		}
		return null;
	}
	
	private static void copyFiles() {
		//---游戏服---
		File srcDir = new File(baseDir, "server");
		File serverDir = new File(destDir, "city-server" + serverId);
		batchDelete(serverDir);
		batchCopy(srcDir, serverDir);
		// copy策划配置表
		batchCopy(dataDir, new File(serverDir, "data"));
		// 修改config.json
		IOUtils.write(new File(serverDir, "config/config.json"), Holder.serverConfig, IOUtils.UTF8);
		// 修改mybatis.xml
		IOUtils.write(new File(serverDir, "config/mybatis.xml"), Holder.serverDbConfig, IOUtils.UTF8);
		// 修改startup.sh
		IOUtils.write(new File(serverDir, "startup.sh"), Holder.startupShell, IOUtils.UTF8);
		
		// nginx config
		if (proxyServerEnable) {
			IOUtils.write(new File(destDir, "__nginx.proxy.conf"), Holder.nginxConfig, IOUtils.UTF8, true);
		}
		
		//---代理服---
		if (proxyServerEnable) {
			srcDir = new File(baseDir, "proxy_server");
			// copy the proxy server's lib
			batchCopy(new File(srcDir, "lib"), new File(serverDir, "proxy/lib"));
			for (int i = 0; i < Holder.proxyServerConfigs.length; i++) {
				File dstDir = new File(serverDir, "proxy/proxy-server" + (i + 1));
				batchCopy(srcDir, dstDir, new FileCopyFilter() {
					@Override
					public boolean doFilter(File src, File dst) {
						// do not copy the lib dir
						return !"lib".equals(src.getName());
					}
				});
				// 修改config.json
				IOUtils.write(new File(dstDir, "config/config.json"), Holder.proxyServerConfigs[i], IOUtils.UTF8);
			}
		}
	}
	
	private static void batchDelete(File file) {
		if (!file.exists()) {
			return;
		}
		if (file.isDirectory()) {
			File[] files = file.listFiles();
			if (files != null) {
				for (File f : files) {
					batchDelete(f);
				}
			}
		}
		boolean b = file.delete();
		if (!b) {
			throw new RuntimeException("try delete file error: " + file.getAbsolutePath());
		}
	}
	
	static interface FileCopyFilter {
		boolean doFilter(File src, File dst);
	}
	
	private static void batchCopy(File src, File dst) {
		batchCopy(src, dst, null);
	}
	
	private static void batchCopy(File src, File dst, FileCopyFilter filter) {
		if (filter != null && !filter.doFilter(src, dst)) {
			return;
		}
		if (!src.exists()) {
			throw new RuntimeException("batch copy error, not found src: " + src.getAbsolutePath());
		}
		if (src.isFile()) {
			tryCreateNewFile(dst);
			copySignleFile(src, dst);
			return;
		}
		tryMkdirs(dst);
		File[] srcs = src.listFiles();
		for (File f : srcs) {
			File d = new File(dst, f.getName());
			batchCopy(f, d);
		}
	}
	
	private static void copySignleFile(File src, File dst) {
		try {
			FileInputStream in = new FileInputStream(src);
			byte[] buf = new byte[10240];
			FileOutputStream out = new FileOutputStream(dst);
			int len;
			while ((len = in.read(buf)) != -1) {
				out.write(buf, 0, len);
			}
			in.close();
			out.flush();
			out.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	private static void tryMkdirs(File f) {
		if (!f.exists()) {
			f.mkdirs();
		}
	}
	
	private static void tryCreateNewFile(File f) {
		if (!f.exists()) {
			try {
				f.createNewFile();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
}
